#ifndef _VL_FILE__H_
#define _VL_FILE__H_

#include <string>
#include <cstdlib>
#include <fstream>
#include <vector>
#include <cstdint>
#include <memory>
#include <stack>
#include <cstdint>

namespace VL {

using VLFileError = int;
// 错误码 - 文件路径
static const VLFileError VL_FILE_ERROR_PATH = 0;


/**
 * @Author: CimZzz
 * @Date: 2023-03-07 18:11:44
 * 
 * 文件异常
 */
struct FileException {
	// 错误码
	VLFileError errorCode;
};

/**
 * @Author: CimZzz
 * @Date: 2023-02-28 16:01:37
 * 
 * 文件类型
 */
enum class FileType {
	// 未知文件类型
	Unknown,
	// 不存在
	NotExists,
	// 文件
	File,
	// 文件夹
	Directory,
};

/**
 * @Author: CimZzz
 * @Date: 2023-02-28 16:05:56
 * 
 * 文件属性
 */
enum class FileProperty {
	// 无属性
	None,
	// 软链接
	Soft,
	// 硬链接
	Hard,
};

/**
 * @Author: CimZzz
 * @Date: 2023-02-28 16:07:18
 * 
 * 文件对象
 */
class File {
public:
	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 16:07:55
	 * 
	 * 构造函数
	 * 
	 * @param path 路径
	 */
	File(const std::string& path);

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 16:09:52
	 * 
	 * 构造函数
	 * 
	 * @param dirPath 文件夹路径
	 * @param relativePath 相对路径
	 */
	explicit File(const std::string& dirPath, const std::string& relativePath);

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 16:29:27
	 * 
	 * 构造函数
	 * 
	 * @param dirFile 父文件夹
	 * @param childPath 子路径
	 */
	explicit File(const File& dirFile, const std::string& childPath);

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 16:32:18
	 * 
	 * 构造函数
	 * 
	 * @param dirFile 父文件夹指针
	 * @param childPath 子路径
	 */
	explicit File(const File* dirFile, const std::string& childPath);

private:
	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 17:59:20
	 * 
	 * 私有构造函数
	 */
	explicit File();

public:

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:25:20
	 * 
	 * 获取文件全路径
	 * 
	 * @return 文件全路径
	 */
	const std::string& getAbsolutePath() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:55:47
	 * 
	 * 获取文件全路径原始字符串
	 * 
	 * @return 文件全路径原始字符串
	 */
	inline const char * getAbsolutePathStr() const {
		return this->getAbsolutePath().c_str();
	}

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:56:33
	 * 
	 * 获取文件名
	 * 
	 * @return 文件名
	 */
	const std::string& getName() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:56:33
	 * 
	 * 获取文件名原始字符串
	 * 
	 * @return 文件名原始字符串
	 */
	inline const char * getNameStr() const {
		return this->getName().c_str();
	}

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:56:53
	 * 
	 * 获取文件扩展名
	 * 
	 * @return 文件扩展名
	 */
	const std::string& getExt() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:56:53
	 * 
	 * 获取文件扩展名原始字符串
	 * 
	 * @return 文件扩展名原始字符串
	 */
	inline const char * getExtStr() const {
		return this->getExt().c_str();
	}

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:57:46
	 * 
	 * 获取无扩展名文件名
	 * 
	 * @return 无扩展名文件名
	 */
	const std::string& getBaseName() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:57:46
	 * 
	 * 获取无扩展名文件名原始字符串
	 * 
	 * @return 无扩展名文件名原始字符串
	 */
	inline const char * getBaseNameStr() const {
		return this->getBaseName().c_str();
	}

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-01 11:04:17
	 * 
	 * 获取父文件夹路径
	 * 
	 * @return 父文件夹路径
	 */
	const std::string& getParentPath() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-01 11:04:17
	 * 
	 * 获取父文件夹路径原始字符串
	 * 
	 * @return 父文件夹路径原始字符串
	 */
	inline const char * getParentPathStr() const {
		return this->getParentPath().c_str();
	}

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 19:09:17
	 * 
	 * 判断文件是否存在
	 * 
	 * @return 如果存在返回 true
	 */
	const bool isExist() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 15:12:05
	 * 
	 * 获取文件类型
	 * 
	 * @param 返回文件类型
	 */
	const FileType getFileType() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-29 16:24:39
	 * 
	 * 判断文件是否为文件夹
	 * 
	 * @return 如果是返回true
	 */
	const bool isDir() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-29 16:25:02
	 * 
	 * 判断文件是否为文件
	 * 
	 * @return 如果是返回true
	 */
	const bool isFile() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 15:10:13
	 * 
	 * 创建文件夹
	 * 
	 * @return 如果成功创建文件夹返回 true
	 */
	const bool mkdir() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-08 15:34:19
	 * 
	 * 嵌套创建文件夹
	 * 
	 * @return 如果嵌套创建成功返回 true
	 */
	const bool mkdirs() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 15:33:11
	 * 
	 * 创建文件
	 * 
	 * @return 如果成功创建文件返回 true
	 */
	const bool touch() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 15:48:17
	 * 
	 * 删除文件或文件夹
	 * 
	 * @return 如果成功删除文件或文件夹, 返回 true
	 */
	const bool remove() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 19:15:20
	 * 
	 * 重命名文件
	 * 
	 * @param file 重命名之后的文件
	 * 
	 * @return 如果重命名成功返回 true
	 */
	const bool rename(const File& file) const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 19:15:20
	 * 
	 * 重命名文件
	 * 
	 * @param file 重命名之后的文件
	 * 
	 * @return 如果重命名成功返回 true
	 */
	const bool rename(const File* file) const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 19:24:59
	 * 
	 * 复制文件
	 * 
	 * @param file 复制之后的文件
	 * 
	 * @return 如果复制成功返回 true
	 */
	const bool copy(const File& file) const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 19:24:59
	 * 
	 * 复制文件
	 * 
	 * @param file 复制之后的文件
	 * 
	 * @return 如果复制成功返回 true
	 */
	const bool copy(const File* file) const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 16:12:37
	 * 
	 * 返回文件夹下所有文件
	 * 
	 * @return 文件列表指针(非空)
	 */
	const std::shared_ptr<std::vector<File>> listFiles() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 18:48:37
	 * 
	 * 获取父目录
	 * 
	 * @return 父目录文件
	 */
	const File getParent() const &;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 18:53:59
	 * 
	 * 判断是否为根目录
	 * 
	 * @return 如果是根目录返回 true
	 */
	const bool isRoot() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2022-02-17 17:00:41
	 * 
	 * 获取文件最后的修改时间
	 * 
	 * @return 修改时间
	 */
	int64_t getModifyTime() const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-08 16:49:12
	 * 
	 * 获取相对路径
	 * 
	 * @param relativeToFile 对比文件
	 * 
	 * @return 相对路径
	 * 
	 * @note 如果当前文件路径不包含对比文件的路径, 则会返回绝对路径
	 */
	const std::string relativeTo(const File* relativeToFile) const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-08 16:49:55
	 * 
	 * 获取相对路径
	 * 
	 * @param relativeToFile 对比文件
	 * 
	 * @return 相对路径
	 * 
	 * @note 如果当前文件路径不包含对比文件的路径, 则会返回绝对路径
	 */
	const std::string relativeTo(const File& relativeToFile) const;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-08 14:36:36
	 * 
	 * 获取文件分割符
	 * 
	 * @return 文件分隔符
	 */
	static const char getFileSeperator();
private:

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:08:47
	 * 
	 * 初始化路径
	 * 
	 * @param path 路径
	 * @param isPartOfPath 明确路径是部分路径
	 */
	void _initFilePath(const std::string& path, bool isPartOfPath);

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:50:03
	 * 
	 * 初始化路径信息
	 */
	void _initFileInfo();

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-07 18:44:03
	 * 
	 * 分隔符栈
	 */
	std::stack<int> sepStack;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:21:06
	 * 
	 * 完整路径
	 */
	std::string absolutePath;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:24:13
	 * 
	 * 文件名
	 */
	std::string name;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:24:28
	 * 
	 * 扩展名
	 */
	std::string ext;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-02-28 18:53:12
	 * 
	 * 文件无后缀名
	 */
	std::string baseName;

	/**
	 * @Author: CimZzz
	 * @Date: 2023-03-01 10:39:37
	 * 
	 * 父路径
	 */
	std::string parentPath;
};


}

#endif // _VL_FILE__H_
